package org.ttitfly.workflow;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.Enumeration;
import java.util.Properties;

import javax.sql.DataSource;

import org.ttitfly.workflow.engine.ProcessFactory;
import org.ttitfly.workflow.engine.basic.XMLProcessFactory;
import org.ttitfly.workflow.engine.persistence.BasicPersistenceService;
import org.ttitfly.workflow.engine.persistence.PersistenceService;
import org.ttitfly.workflow.exception.WorkflowInitException;
import org.ttitfly.workflow.factory.DefaultObjectFactory;
import org.ttitfly.workflow.factory.EJBObjectCreator;
import org.ttitfly.workflow.factory.ObjectCreator;
import org.ttitfly.workflow.factory.ObjectFactory;
import org.ttitfly.workflow.factory.ObjectNameUnavailableException;
import org.ttitfly.workflow.factory.ReflectClassCreator;


/**
 * 工作流上下文环境
 * 
 * @author 潘海春
 * @version 2008-12-24
 */
public class WorkflowContext {

	/** 反射对象生成策略 */
	private static final String REFLECT_CREATOR = "reflect";

	/** ejb对象生成策略 */
	private static final String EJB_LOCAL_CREATOR = "ejb";

	/** 默认对象生成策略 */
	private static final String DEFALUT_CREATOR = REFLECT_CREATOR;

	/** 对象创建器的类型 */
	private static final String OBJECT_CREATOR_TYPE = "object-creator.type";

	/** 对象创建器属性前缀 */
	private static final String OBJECT_CREATOR_PROPS_PREFIX = "object-creator.props.";

	/** 进程工厂 */
	private static final String PROCESS_FACTORY = "process-factory";

	/** 持久化服务对象 */
	private static final String PERSISTENCE_SERVICE = "persistence-service";

	/** 数据源 */
	private static final String DATASOURCE = "persistence.data-source";

	/** 流程定义文件存放目录 */
	private static final String PROCESS_DIR = "process-dir";

	/** 数据源 */
	private DataSource dataSource;

	/** 文件地址 */
	protected Properties properties;

	/** 将要生成的会话管理器 */
	protected SessionEstablishment sessionEstablishment = null;

	/**
	 * 构造函数
	 */
	public WorkflowContext() {
		this("");
	}

	/**
	 * 构造函数
	 * 
	 * @param dataSource
	 */
	public WorkflowContext(DataSource dataSource) {
		this("", dataSource);
	}

	/**
	 * 构造函数
	 * 
	 * @param properties
	 */
	public WorkflowContext(Properties properties) {
		this(properties, null);
	}

	/**
	 * 构造函数
	 * 
	 * @param properties
	 * @param dataSource
	 */
	public WorkflowContext(Properties properties, DataSource dataSource) {
		this.properties = properties;
		this.dataSource = dataSource;
	}

	/**
	 * 构造函数
	 * 
	 * @param configFile
	 *            配置文件路径
	 */
	public WorkflowContext(String configFile) {
		this(configFile, null);
	}

	/**
	 * 构造函数
	 * 
	 * @param properties
	 * @param dataSource
	 */
	public WorkflowContext(String configFile, DataSource dataSource) {
		if (configFile == null || "".equals(configFile = configFile.replaceAll("(\\\\|/)+", File.separator).trim())) {
			configFile = null;
			URL url = getClass().getClassLoader().getResource("workflow.properties");
			if (url != null) {
				configFile = url.getPath();
			}
		}
		properties = new Properties();
		if (configFile != null) {
			File file = new File(configFile);
			if (file.exists() && file.isFile()) {
				try {
					properties.load(new FileInputStream(configFile));
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
		}
		this.dataSource = dataSource;
	}

	/**
	 * 构建 SessionEstablishment
	 * 
	 * @return
	 * @throws Exception
	 */
	public synchronized SessionEstablishment buildSessionEstablishment()
			throws WorkflowInitException {
		if (sessionEstablishment == null) {
			refresh();
		}
		return sessionEstablishment;
	}

	/**
	 * 创建工作流上下文
	 * 
	 * @throws Exception
	 */
	protected void refresh() throws WorkflowInitException {
		// 创建对象工厂
		ObjectFactory objectFactory = buildObjectFactory();

		ProcessFactory processFactory = buildProcessFactory(objectFactory);

		PersistenceService persistenceService = buildPersistenceService(objectFactory);

		// 初始化会话发布管理器
		sessionEstablishment = new ThreadSessionEstablishment(processFactory, persistenceService);
	}

	/**
	 * 构建持久化服务
	 * 
	 * @param objectFactory
	 * @return
	 * @throws WorkflowInitException
	 */
	private PersistenceService buildPersistenceService(
			ObjectFactory objectFactory) throws WorkflowInitException {
		String persistenceServiceBeanName = properties.getProperty(PERSISTENCE_SERVICE);
		if (persistenceServiceBeanName != null && !"".equals(persistenceServiceBeanName = persistenceServiceBeanName.trim())) {
			try {
				return (PersistenceService) objectFactory.getBean(persistenceServiceBeanName);
			} catch (ObjectNameUnavailableException e) {
				throw new WorkflowInitException(e);
			}
		}
		if (dataSource == null) {
			String dataSourceBeanName = properties.getProperty(DATASOURCE);
			if (dataSourceBeanName != null && !"".equals(dataSourceBeanName = dataSourceBeanName.trim())) {
				try {
					dataSource = (DataSource) objectFactory.getBean(dataSourceBeanName);
				} catch (ObjectNameUnavailableException e) {
					throw new WorkflowInitException(e);
				}
			}
		}
		if (dataSource != null) {
			return new BasicPersistenceService(dataSource);
		}
		throw new WorkflowInitException("build persistence service fail!");
	}

	/**
	 * 创建流程工厂
	 * 
	 * @param objectFactory
	 * @return
	 * @throws WorkflowInitException
	 */
	private ProcessFactory buildProcessFactory(ObjectFactory objectFactory) throws WorkflowInitException {
		String processFactoryBeanName = properties.getProperty(PROCESS_FACTORY);
		ProcessFactory processFactory = null;
		if (processFactoryBeanName != null && !"".equals(processFactoryBeanName = processFactoryBeanName.trim())) {
			try {
				processFactory = (ProcessFactory) objectFactory.getBean(processFactoryBeanName);
			} catch (ObjectNameUnavailableException e) {
				throw new WorkflowInitException(e);
			}
		} else {
			String dir = properties.getProperty(PROCESS_DIR);
			if (dir == null || "".equals(dir = dir.trim())) {
				dir = getClass().getClassLoader().getResource("processes").getPath();
			}
			processFactory = new XMLProcessFactory(objectFactory, new File(dir));
		}
		return processFactory;
	}

	/**
	 * 创建对象工厂
	 * 
	 * @return
	 */
	protected ObjectFactory buildObjectFactory() throws WorkflowInitException {
		ObjectCreator creator = null;
		String objectCreatorType = properties.getProperty(OBJECT_CREATOR_TYPE);
		if (objectCreatorType == null || "".equals(objectCreatorType = objectCreatorType.trim())) {
			// 未定义则使用默认的对象创建器
			objectCreatorType = DEFALUT_CREATOR;
		}
		if (REFLECT_CREATOR.equalsIgnoreCase(objectCreatorType)) {
			// jdk反射对象创建器
			creator = new ReflectClassCreator();
		} else {
			// 构造对象创建器的参数属性
			Properties props = new Properties();
			Enumeration<Object> enumeration = properties.elements();
			while (enumeration.hasMoreElements()) {
				String key = (String) enumeration.nextElement();
				if (key.startsWith(OBJECT_CREATOR_PROPS_PREFIX)) {
					String propertyName = key.replaceAll(OBJECT_CREATOR_PROPS_PREFIX, "");
					props.put(propertyName, properties.getProperty(key));
				}
			}
			if (EJB_LOCAL_CREATOR.equalsIgnoreCase(objectCreatorType)) {
				// ejb对象创建器
				creator = new EJBObjectCreator(props);
			} else {
				try {
					// 反射直接根据类名创建对象创建器
					Class<?> clazz = Class.forName(objectCreatorType);
					Constructor<?> c = null;
					try {
						c = clazz.getConstructor(Properties.class);
					} catch (Exception e) {
						c = null;
					}
					if (c != null) {
						// 如果包含Properties类型参数的构造函数则调用该构造函数创建
						creator = (ObjectCreator) c.newInstance(props);
					} else {
						creator = (ObjectCreator) clazz.newInstance();
					}
				} catch (Exception e) {
					throw new WorkflowInitException(e);
				}
			}
		}
		return new DefaultObjectFactory(creator);
	}

}
